﻿using Cordyceps.Micro.Elastic.HealthChecks;
using Cordyceps.Micro.Elastic.Options;
using Elastic.Clients.Elasticsearch;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Options;
using HealthStatus = Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus;

namespace Cordyceps.Micro.Elastic.Extensions;

public static class ElasticsearchExtensions
{
    /// <summary>
    ///     添加Elasticsearch服务
    /// </summary>
    /// <param name="services"></param>
    /// <param name="configure"></param>
    /// <returns></returns>
    public static IServiceCollection AddElasticsearch(this IServiceCollection services,
        Action<ElasticsearchOptions> configure)
    {
        services.Configure(configure);
        services.AddSingleton<IElasticsearchClientFactory, ElasticsearchClientFactory>();

        services.AddSingleton(sp =>
        {
            var factory = sp.GetRequiredService<IElasticsearchClientFactory>();
            return factory.CreateClient();
        });

        return services;
    }

    /// <summary>
    ///     添加命名Elasticsearch客户端（多集群支持）
    /// </summary>
    /// <param name="services"></param>
    /// <param name="name"></param>
    /// <param name="configure"></param>
    /// <returns></returns>
    public static IServiceCollection AddElasticsearch(this IServiceCollection services, string name,
        Action<ElasticsearchOptions> configure)
    {
        services.Configure(name, configure);

        services.AddKeyedSingleton(name, (sp, key) =>
        {
            var factory = sp.GetRequiredService<IElasticsearchClientFactory>();
            var optionsMonitor = sp.GetRequiredService<IOptionsMonitor<ElasticsearchOptions>>();
            var options = optionsMonitor.Get(name);
            return factory.CreateClient(options);
        });

        return services;
    }

    /// <summary>
    ///     添加健康检查服务
    /// </summary>
    public static IHealthChecksBuilder AddElasticsearchHealthCheck(
        this IHealthChecksBuilder builder,
        string name = "elasticsearch",
        HealthStatus? failureStatus = null,
        IEnumerable<string>? tags = null,
        TimeSpan? timeout = null)
    {
        return builder.Add(new HealthCheckRegistration(
            name,
            sp =>
            {
                var factory = sp.GetRequiredService<IElasticsearchClientFactory>();
                var client = sp.GetRequiredService<ElasticsearchClient>();
                return new ElasticsearchHealthCheck(factory, client);
            },
            failureStatus,
            tags,
            timeout));
    }
}